home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / file / managers / mc-3.2 / mc-3 / mc-3.2.1 / vfs / tar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-17  |  39.2 KB  |  1,500 lines

  1. /* Virtual File System: GNU Tar file system.
  2.    Copyright (C) 1995 The Free Software Foundation
  3.    
  4.    Written by: 1995 Jakub Jelinek
  5.  
  6.    This program is free software; you can redistribute it and/or modify
  7.    it under the terms of the GNU General Public License as published by
  8.    the Free Software Foundation; either version 2 of the License, or
  9.    (at your option) any later version.
  10.  
  11.    This program is distributed in the hope that it will be useful,
  12.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with this program; if not, write to the Free Software
  18.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include <config.h>
  21. #include <stdio.h>
  22. #include <ctype.h>
  23. #include <string.h>
  24. #include <stdlib.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <fcntl.h>
  28. #include <unistd.h>
  29. #include <signal.h>
  30. #include <sys/wait.h>
  31. #include <errno.h>
  32. #include <time.h>
  33. #include "../src/fs.h"
  34. #include "../src/util.h"
  35. #include "../src/mem.h"
  36. #include "../src/mad.h"
  37. #include "vfs.h"
  38. #include "tar.h"
  39. #include "names.h"
  40.  
  41. /* The limit for a compressed tar file to be loaded in core */
  42. int tar_gzipped_memlimit = 1*1024*1024;
  43.  
  44. /* used to rotate the dash */
  45. int dash_number = 0;
  46.  
  47. /* In order not to include all dialoging stuff, I'm not including dialog.h
  48.    just for this function */
  49. extern void *message (int error, char *header, char *text,...);
  50.  
  51. #define    isodigit(c)    ( ((c) >= '0') && ((c) <= '7') )
  52. /*
  53.  * Quick and dirty octal conversion.
  54.  *
  55.  * Result is -1 if the field is invalid (all blank, or nonoctal).
  56.  */
  57. long from_oct (int digs, char *where)
  58. {
  59.     register long value;
  60.  
  61.     while (isspace (*where)) {    /* Skip spaces */
  62.     where++;
  63.     if (--digs <= 0)
  64.         return -1;        /* All blank field */
  65.     }
  66.     value = 0;
  67.     while (digs > 0 && isodigit (*where)) {    /* Scan till nonoctal */
  68.     value = (value << 3) | (*where++ - '0');
  69.     --digs;
  70.     }
  71.  
  72.     if (digs > 0 && *where && !isspace (*where))
  73.     return -1;        /* Ended on non-space/nul */
  74.  
  75.     return value;
  76. }
  77.  
  78. static struct tarfs_archive *first_archive = NULL;
  79. static int tarerrno = 0;
  80. static struct stat hstat;        /* Stat struct corresponding */
  81. static char *current_file_name, *current_link_name;
  82. static struct tarfs_entry *tarfs_find_entry (struct tarfs_entry *dir, char *name, int make_dirs);
  83.  
  84. void tarfs_fill_names (void (*func)(char *))
  85. {
  86.     struct tarfs_archive *a = first_archive;
  87.     char *name;
  88.     
  89.     while (a){
  90.     name = copy_strings ("tar:", a->name, "/",
  91.                  a->current_dir->name, 0);
  92.     (*func)(name);
  93.     free (name);
  94.     a = a->next;
  95.     }
  96. }
  97.  
  98. static void make_dot_doubledot (struct tarfs_entry *ent)
  99. {
  100.     struct tarfs_entry *entry = (struct tarfs_entry *)
  101.     xmalloc (sizeof (struct tarfs_entry), "Tar: tarfs_entry");
  102.     struct tarfs_entry *parentry = ent->dir;
  103.     struct tarfs_inode *inode = ent->inode, *parent;
  104.     
  105.     parent = (parentry != NULL) ? parentry->inode : NULL;
  106.     entry->name = strdup (".");
  107.     entry->has_changed = 0;
  108.     entry->header_offset = -1;
  109.     entry->header_size = 0;
  110.     entry->extended_offset = -1;
  111.     entry->extended_size = 0;
  112.     entry->inode = inode;
  113.     entry->dir = ent;
  114.     inode->first_in_subdir = entry;
  115.     inode->last_in_subdir = entry;
  116.     inode->nlink++;
  117.     entry->next_in_dir = (struct tarfs_entry *)
  118.     xmalloc (sizeof (struct tarfs_entry), "Tar: tarfs_entry");
  119.     entry=entry->next_in_dir;
  120.     entry->name = strdup ("..");
  121.     entry->has_changed = 0;
  122.     entry->header_offset = -1;
  123.     entry->header_size = 0;
  124.     entry->extended_offset = -1;
  125.     entry->extended_size = 0;
  126.     inode->last_in_subdir = entry;
  127.     entry->next_in_dir = NULL;
  128.     if (parent != NULL) {
  129.         entry->inode = parent;
  130.         entry->dir = parentry;
  131.         parent->nlink++;
  132.     } else {
  133.         entry->inode = inode;
  134.         entry->dir = ent;
  135.         inode->nlink++;
  136.     }
  137. }
  138.  
  139. static struct tarfs_entry *generate_entry (struct tarfs_archive *archive, 
  140.     char *name, struct tarfs_entry *parentry, mode_t mode)
  141. {
  142.     mode_t myumask;
  143.     struct tarfs_inode *inode, *parent; 
  144.     struct tarfs_entry *entry;
  145.  
  146.     parent = (parentry != NULL) ? parentry->inode : NULL;
  147.     entry = (struct tarfs_entry *)
  148.     xmalloc (sizeof (struct tarfs_entry), "Tar: tarfs_entry");
  149.     
  150.     entry->name = strdup (name);
  151.     entry->has_changed = 0;
  152.     entry->header_offset = -1;
  153.     entry->header_size = 0;
  154.     entry->extended_offset = -1;
  155.     entry->extended_size = 0;
  156.     entry->next_in_dir = NULL;
  157.     entry->dir = parentry;
  158.     if (parent != NULL) {
  159.         parent->last_in_subdir->next_in_dir = entry;
  160.         parent->last_in_subdir = entry;
  161.     }
  162.     inode = (struct tarfs_inode *)
  163.     xmalloc (sizeof (struct tarfs_inode), "Tar: tarfs_inode");
  164.     entry->inode = inode;
  165.     inode->local_filename = NULL;
  166.     inode->has_changed = 0;
  167.     inode->is_open = 0;
  168.     inode->linkname = 0;
  169.     inode->inode = (archive->__inode_counter)++;
  170.     inode->dev = archive->rdev;
  171.     inode->archive = archive;
  172.     inode->data_offset = -1;
  173.     myumask = umask (022);
  174.     umask (myumask);
  175.     inode->mode = mode & ~myumask;
  176.     mode = inode->mode;
  177.     inode->rdev = 0;
  178.     inode->uid = getuid ();
  179.     inode->gid = getgid ();
  180.     inode->std = 1;
  181.     inode->size = 0;
  182.     inode->mtime = time (NULL);
  183.     inode->atime = inode->mtime;
  184.     inode->ctime = inode->mtime;
  185.     inode->nlink = 1;
  186.     if (S_ISDIR (mode)) {
  187.         inode->linkflag = LF_DIR;
  188.         make_dot_doubledot (entry);
  189.     } else if (S_ISLNK (mode)) {
  190.         inode->linkflag = LF_SYMLINK;
  191.     } else if (S_ISCHR (mode)) {
  192.         inode->linkflag = LF_CHR;
  193.     } else if (S_ISBLK (mode)) {
  194.         inode->linkflag = LF_BLK;
  195.     } else if (S_ISFIFO (mode) || S_ISSOCK (mode)) {
  196.         inode->linkflag = LF_FIFO;
  197.     } else {
  198.         inode->linkflag = LF_NORMAL;
  199.     }
  200.     return entry;
  201. }
  202.  
  203. static void free_entries (struct tarfs_entry *entry)
  204. {
  205.     return;
  206. }
  207.  
  208. static void free_archive (struct tarfs_archive *archive)
  209. {
  210.     long l;
  211.  
  212.     if (archive->is_gzipped == targz_growing) {
  213.         free (archive->block_first);
  214.         if (archive->block_ptr != NULL) {
  215.             for (l = 0; l < archive->count_blocks; l++)
  216.                 free (archive->block_ptr [l]);
  217.             free (archive->block_ptr);
  218.         }
  219.     } else {
  220.         if (archive->is_gzipped == tar_uncompressed_local) {
  221.             mc_unlink (archive->tmpname);
  222.             free (archive->tmpname);
  223.         }
  224.     if (archive->fd != -1)
  225.         mc_close(archive->fd);
  226.     }
  227.     free_entries (archive->root_entry);
  228.     
  229.     free (archive->name);
  230.     free (archive);
  231. }
  232.  
  233. static INLINE int gzip_limit_ok (int size)
  234. {
  235.     return (size <= tar_gzipped_memlimit || tar_gzipped_memlimit < 0);
  236. }
  237.  
  238. /* So we have to decompress it... 
  239.  * It is not that easy, because we would like to handle all the files
  240.  * from all the vfs's. So, we do this like this:
  241.  * we run a pipe:
  242.  *    for (;;) mc_read | gzip -cdf | store into growing buffer
  243.  *
  244.  * Returns: 0 on failure
  245.  */
  246. static INLINE int load_compressed_tar (struct tarfs_archive *current_archive,
  247.                     int size, int fd)
  248. {    
  249.     int pipehandle, i;
  250.     long l, l2;
  251.     union record *ur;
  252.     pid_t p;
  253.     
  254.     l2 = 0;
  255.     current_archive->is_gzipped = targz_growing;
  256.     size = (size + RECORDSIZE - 1) / RECORDSIZE * RECORDSIZE;
  257.     current_archive->block_first =
  258.     (union record *) xmalloc (size, "Tar.gz growing buffers");
  259.     current_archive->count_first = size / RECORDSIZE;
  260.     current_archive->count_blocks = 0;
  261.     current_archive->block_ptr = NULL;
  262.     current_archive->root_entry = NULL;
  263.     
  264.     pipehandle = mc_doublepopen (fd, -1, &p, "gzip", "gzip", "-cdf", NULL);
  265.     if (pipehandle == -1)
  266.     {
  267.     free (current_archive->block_first);
  268.     free (current_archive);
  269.     mc_close (fd);
  270.     return 0;
  271.     }
  272.     ur = current_archive->block_first;
  273.     l = 0;
  274.     while ((i = read (pipehandle, (char *) ur, RECORDSIZE)) == RECORDSIZE) {
  275.     l++;
  276.     if (l >= current_archive->count_first) {
  277.         l2 = l - current_archive->count_first;
  278.         if (l2 % TAR_GROWING_CHUNK_SIZE)
  279.         ur++;
  280.         else {
  281.         union record **tmp = (union record **)
  282.             xmalloc ((++current_archive->count_blocks) *
  283.                  sizeof (union record **), "Tar: Growing buffers");
  284.         
  285.         if (current_archive->block_ptr != NULL) {
  286.             bcopy (current_archive->block_ptr, tmp, 
  287.                (current_archive->count_blocks - 1) *
  288.                sizeof (union record **));
  289.             free (current_archive->block_ptr);
  290.         }
  291.         current_archive->block_ptr = tmp;
  292.         ur = (union record *)
  293.             xmalloc (TAR_GROWING_CHUNK_SIZE * RECORDSIZE,
  294.                  "Tar: Growing buffers");
  295.         current_archive->block_ptr [current_archive->count_blocks - 1] = ur;
  296.         }
  297.     } else
  298.         ur++;
  299.     if ((dash_number++ % 64) == 0)
  300.         rotate_dash ();
  301.     }
  302.     i = mc_doublepclose (pipehandle, p);
  303.     mc_close (fd);
  304.     if (i == -1) {
  305.     free_archive (current_archive);
  306.     return 0;
  307.     }
  308.     current_archive->current_record = current_archive->block_first;
  309.     return 1;
  310. }
  311.  
  312. /* Returns a file handle of the opened local tar file or -1 on error */
  313. static INLINE int uncompress_tar_file  (struct tarfs_archive *current_archive,
  314.                     int size, int fd)
  315. {
  316.     FILE *f;
  317.     char *command;
  318.     int i, result;
  319.     int dash_number = 0;
  320.     char buffer [8192];    /* Changed to 8K: better transfer size */
  321.     
  322.     current_archive->is_gzipped = tar_uncompressed_local;
  323.     current_archive->tmpname = strdup (tmpnam (NULL));
  324.     
  325.     /* Some security is sometimes neccessary :) */        
  326.     command = copy_strings ("touch ", current_archive->tmpname,
  327.                 " ; chmod 0600 ", current_archive->tmpname,
  328.                             " ; gzip -cdf 2>/dev/null >", current_archive->tmpname, NULL);
  329.     
  330.     if ((f = popen (command, "w")) == NULL) {
  331.     mc_close (fd);
  332.     free_archive (current_archive);
  333.     free (command);
  334.     return -1;
  335.     }
  336.     free (command);
  337.     
  338.     while ((i = mc_read (fd, buffer, sizeof (buffer))) > 0){
  339.     if ((dash_number++ % 64) == 0)
  340.         rotate_dash ();
  341.     fwrite (buffer, 1, i, f);
  342.     }
  343.     
  344.     pclose (f);
  345.     mc_close (fd);
  346.     result = mc_open (current_archive->tmpname, O_RDONLY);
  347.     if (result == -1){
  348.     free_archive (current_archive);
  349.     return -1;
  350.     }
  351.     return result;
  352. }
  353.  
  354. /* Returns fd of the open tar file */
  355. static int open_tar_archive (char *name, struct tarfs_archive **pparc)
  356. {
  357.     static dev_t __tar_no = 0;
  358.     int result;
  359.     long size;
  360.     mode_t mode;
  361.     struct tarfs_archive *current_archive;
  362.     static struct tarfs_entry *root_entry;
  363.     
  364.     result = mc_open (name, O_RDONLY);
  365.     if (result == -1)
  366.         return -1;
  367.     
  368.     current_archive = (struct tarfs_archive *)
  369.                       xmalloc (sizeof (struct tarfs_archive), "Tar archive");
  370.     current_archive->current_tar_position = 0;
  371.     current_archive->name = strdup (name);
  372.     current_archive->__inode_counter = 0;
  373.     mc_stat (name, &(current_archive->tarstat));
  374.     current_archive->rdev = __tar_no++;
  375.     current_archive->next = first_archive;
  376.     current_archive->fd_usage = 0;
  377.     current_archive->fd = -1;
  378.     size = is_gunzipable (result);
  379.     mc_lseek (result, 0, SEEK_SET);
  380.  
  381.     /* Find out the method to handle this tar file */
  382.     if (size > 0 && gzip_limit_ok (size)) {
  383.     if (load_compressed_tar (current_archive, size, result) == 0)
  384.         return -1;
  385.     result = 0;
  386.     } else if (size > 0) {
  387.     result = uncompress_tar_file (current_archive, size, result);
  388.     if (result == -1)
  389.         return -1;
  390.     } else {
  391.         current_archive->is_gzipped = tar_normal;
  392.     }
  393.    
  394.     current_archive->fd = result;
  395.     first_archive = current_archive;
  396.     mode = current_archive->tarstat.st_mode & 07777;
  397.     if (mode & 0400)
  398.         mode |= 0100;
  399.     if (mode & 0040)
  400.         mode |= 0010;
  401.     if (mode & 0004)
  402.         mode |= 0001;
  403.     mode |= S_IFDIR;
  404.     root_entry = generate_entry (current_archive, "/", NULL, mode);
  405.     root_entry->inode->uid = current_archive->tarstat.st_uid;
  406.     root_entry->inode->gid = current_archive->tarstat.st_gid;
  407.     root_entry->inode->atime = current_archive->tarstat.st_atime;
  408.     root_entry->inode->ctime = current_archive->tarstat.st_ctime;
  409.     root_entry->inode->mtime = current_archive->tarstat.st_mtime;
  410.     current_archive->root_entry = root_entry;
  411.     current_archive->current_dir = root_entry;
  412.     
  413.     *pparc = current_archive;
  414.  
  415.     return result;
  416. }
  417.  
  418. static int get_current_position (struct tarfs_archive *archive, int tard)
  419. {
  420.     return archive->current_tar_position;
  421. }
  422.  
  423. static union record *find_current_record (struct tarfs_archive *archive, long pos)
  424. {
  425.     long l, l2;
  426.     static union record *ur;
  427.         
  428.     l = pos / RECORDSIZE;
  429.     if (l >= archive->count_first) {
  430.     l2 = l - archive->count_first;
  431.         ur = archive->block_ptr [l2 / TAR_GROWING_CHUNK_SIZE] 
  432.              + (l2 % TAR_GROWING_CHUNK_SIZE);
  433.     } else
  434.         ur = archive->block_first + l;
  435.     return ur;
  436. }
  437.  
  438. static union record rec_buf;
  439.  
  440. static union record *get_next_record (struct tarfs_archive *archive, int tard)
  441. {
  442.     if (archive->is_gzipped == targz_growing) {
  443.         bcopy (archive->current_record, rec_buf.charptr, RECORDSIZE);
  444.         archive->current_record = find_current_record (archive, archive->current_tar_position + RECORDSIZE); 
  445.     } else if (mc_read (tard, rec_buf.charptr, RECORDSIZE) != RECORDSIZE)
  446.     return NULL;        /* An error has occurred */
  447.     archive->current_tar_position += RECORDSIZE;
  448.     return &rec_buf;
  449. }
  450.  
  451. static void skip_n_records (struct tarfs_archive *archive, int tard, int n)
  452. {
  453.     if (archive->is_gzipped == targz_growing)
  454.         archive->current_record = find_current_record (archive, archive->current_tar_position + n * RECORDSIZE);
  455.     else
  456.         mc_lseek (tard, n * RECORDSIZE, SEEK_CUR);
  457.     archive->current_tar_position += n * RECORDSIZE;
  458. }
  459.  
  460. /*
  461.  * Return 1 for success, 0 if the checksum is bad, EOF on eof,
  462.  * 2 for a record full of zeros (EOF marker).
  463.  *
  464.  */
  465. static int read_header (struct tarfs_archive *archive, int tard)
  466. {
  467.     register int i;
  468.     register long sum, signed_sum, recsum;
  469.     register char *p;
  470.     register union record *header;
  471.     char **longp;
  472.     char *bp, *data;
  473.     int size, written;
  474.     static char *next_long_name = NULL, *next_long_link = NULL;
  475.     long header_position = get_current_position (archive, tard);
  476.  
  477.   recurse:
  478.  
  479.     header = get_next_record (archive, tard);
  480.     if (NULL == header)
  481.     return EOF;
  482.  
  483.     recsum = from_oct (8, header->header.chksum);
  484.  
  485.     sum = 0; signed_sum = 0;
  486.     p = header->charptr;
  487.     for (i = sizeof (*header); --i >= 0;) {
  488.             /*
  489.          * We can't use unsigned char here because of old compilers,
  490.          * e.g. V7.
  491.          */
  492.     signed_sum += *p;
  493.     sum += 0xFF & *p++;
  494.     }
  495.  
  496.     /* Adjust checksum to count the "chksum" field as blanks. */
  497.     for (i = sizeof (header->header.chksum); --i >= 0;) {
  498.     sum -= 0xFF & header->header.chksum[i];
  499.     signed_sum -= (char) header->header.chksum[i];
  500.     }
  501.     sum += ' ' * sizeof header->header.chksum;
  502.     signed_sum += ' ' * sizeof header->header.chksum;
  503.  
  504.     if (sum == 8 * ' ') {
  505.     /*
  506.          * This is a zeroed record...whole record is 0's except
  507.          * for the 8 blanks we faked for the checksum field.
  508.          */
  509.     return 2;
  510.     }
  511.     if (sum != recsum && signed_sum != recsum)
  512.     return 0;
  513.  
  514.     /*
  515.      * Good record.  Decode file size and return.
  516.      */
  517.     if (header->header.linkflag == LF_LINK || header->header.linkflag == LF_DIR)
  518.     hstat.st_size = 0;    /* Links 0 size on tape */
  519.     else
  520.     hstat.st_size = from_oct (1 + 12, header->header.size);
  521.  
  522.     header->header.arch_name[NAMSIZ - 1] = '\0';
  523.     if (header->header.linkflag == LF_LONGNAME
  524.     || header->header.linkflag == LF_LONGLINK) {
  525.     longp = ((header->header.linkflag == LF_LONGNAME)
  526.          ? &next_long_name
  527.          : &next_long_link);
  528.  
  529.     if (*longp)
  530.         free (*longp);
  531.     bp = *longp = (char *) xmalloc (hstat.st_size, "Tar: Long name");
  532.  
  533.     for (size = hstat.st_size;
  534.          size > 0;
  535.          size -= written) {
  536.         data = get_next_record (archive, tard)->charptr;
  537.         if (data == NULL) {
  538.         message (1, " Error ", "Unexpected EOF on archive file");
  539.         return 0;
  540.         }
  541.         written = RECORDSIZE;
  542.         if (written > size)
  543.         written = size;
  544.  
  545.         bcopy (data, bp, written);
  546.         bp += written;
  547.     }
  548.     bp [hstat.st_size - 1] = 0;    /* just to make sure */
  549.     goto recurse;
  550.     } else {
  551.     struct tarfs_entry *entry, *pent;
  552.     struct tarfs_inode *inode;
  553.     long data_position;
  554.     char *p, *q;
  555.     int len;
  556.     int isdir = 0;
  557.  
  558.     current_file_name = (next_long_name
  559.                  ? next_long_name
  560.                  : strdup (header->header.arch_name));
  561.     len = strlen (current_file_name);
  562.     if (current_file_name[len - 1] == '/') {
  563.         current_file_name[len - 1] = 0;
  564.         isdir = 1;
  565.     }
  566.  
  567.     current_link_name = (next_long_link
  568.                  ? next_long_link
  569.                  : strdup (header->header.arch_linkname));
  570.     len = strlen (current_link_name);
  571.     if (current_link_name [len - 1] == '/')
  572.         current_link_name[len - 1] = 0;
  573.  
  574.     next_long_link = next_long_name = NULL;
  575.  
  576.     data_position = get_current_position (archive, tard);
  577.     
  578.     p = strrchr (current_file_name, '/');
  579.     if (p == NULL) {
  580.         p = current_file_name;
  581.         q = current_file_name + strlen (current_file_name); /* "" */
  582.     } else {
  583.         *(p++) = 0;
  584.         q = current_file_name;
  585.     }
  586.         
  587.     pent = tarfs_find_entry (archive->root_entry, q, 1);
  588.     if (pent == NULL) {
  589.         message (1, " Error ", "Inconsistent tar archive");
  590.     }
  591.  
  592.     entry = (struct tarfs_entry *) xmalloc (sizeof (struct tarfs_entry), "Tar: tarfs_entry");
  593.     entry->name = strdup (p);
  594.     entry->has_changed = 0;
  595.     entry->header_offset = header_position;
  596.     entry->header_size = data_position - header_position;
  597.     entry->extended_offset = -1;
  598.     entry->extended_size = 0;
  599.     entry->next_in_dir = NULL;
  600.     entry->dir = pent;
  601.     if (pent != NULL) {
  602.         pent->inode->last_in_subdir->next_in_dir = entry;
  603.         pent->inode->last_in_subdir = entry;
  604.     }
  605.     free (current_file_name);
  606.  
  607.     if (header->header.linkflag == LF_LINK) {
  608.         pent = tarfs_find_entry (archive->root_entry, current_link_name, 0);
  609.         if (pent == NULL) {
  610.             message (1, " Error ", "Inconsistent tar archive");
  611.         } else {
  612.         entry->inode = pent->inode;
  613.         pent->inode->nlink++;
  614.         free (current_link_name);
  615.         if (header->header.isextended) {
  616.                 entry->extended_offset = data_position;
  617.                 while (get_next_record (archive, tard)->ext_hdr.isextended);
  618.                 data_position = get_current_position (archive, tard);
  619.                 entry->extended_size = data_position - entry->extended_offset;
  620.             }
  621.             return 1;
  622.         }
  623.     }
  624.     inode = (struct tarfs_inode *) xmalloc (sizeof (struct tarfs_inode), "Tar: tarfs_inode");
  625.     entry->inode = inode;
  626.     inode->local_filename = NULL;
  627.     inode->has_changed = 0;
  628.     inode->is_open = 0;
  629.     inode->inode = (archive->__inode_counter)++;
  630.     inode->nlink = 1;
  631.     inode->dev = archive->rdev;
  632.     inode->archive = archive;
  633.     inode->data_offset = data_position;
  634.     inode->mode = from_oct (8, header->header.mode);
  635.     inode->rdev = 0;
  636.     if (!strcmp (header->header.magic, TMAGIC)) {
  637.         inode->uid = *header->header.uname ? finduid (header->header.uname) :
  638.                                              from_oct (8, header->header.uid);
  639.         inode->gid = *header->header.gname ? findgid (header->header.gname) :
  640.                                              from_oct (8, header->header.gid);
  641.         switch (header->header.linkflag) {
  642.             case LF_BLK:
  643.             case LF_CHR:
  644.                 inode->rdev = (from_oct (8, header->header.devmajor) << 8) |
  645.                                from_oct (8, header->header.devminor);
  646.         }
  647.         inode->std = 1;
  648.     } else { /* Old Unix tar */
  649.         inode->uid = from_oct (8, header->header.uid);
  650.         inode->gid = from_oct (8, header->header.gid);
  651.         inode->std = 0;
  652.     }
  653.     inode->size = hstat.st_size;
  654.     inode->mtime = from_oct (1 + 12, header->header.mtime);
  655.     inode->atime = from_oct (1 + 12, header->header.atime);
  656.     inode->ctime = from_oct (1 + 12, header->header.ctime);
  657.     inode->linkflag = header->header.linkflag;
  658.     if (*current_link_name) {
  659.         inode->linkname = current_link_name;
  660.     } else {
  661.         free (current_link_name);
  662.         inode->linkname = NULL;
  663.     }
  664.     if (inode->linkflag == LF_DIR || isdir) {
  665.         inode->mode |= S_IFDIR;
  666.         make_dot_doubledot (entry);
  667.     }
  668.     if (header->header.isextended) {
  669.         entry->extended_offset = data_position;
  670.         while (get_next_record (archive, tard)->ext_hdr.isextended);
  671.         inode->data_offset = get_current_position (archive, tard);
  672.         entry->extended_size = inode->data_offset - entry->extended_offset;
  673.     }
  674.     return 1;
  675.     }
  676. }
  677.  
  678. /*
  679.  * Main loop for reading an archive.
  680.  * Returns 0 on success, -1 on error.
  681.  */
  682. int read_tar_archive (char *name, struct tarfs_archive **pparc)
  683. {
  684.     int status = 3;        /* Initial status at start of archive */
  685.     int prev_status;
  686.     int tard;
  687.     struct tarfs_archive *archive;
  688.  
  689.     if ((tard = open_tar_archive (name, &archive)) == -1) {    /* Open for reading */
  690.         message (1, " Error ", "Couldn't open tar archive\n%s", name);
  691.     return -1;
  692.     }
  693.  
  694.     for (;;) {
  695.     prev_status = status;
  696.     status = read_header (archive, tard);
  697.     switch (status) {
  698.  
  699.     case 1:        /* Valid header */
  700.         skip_n_records (archive, tard, (hstat.st_size + RECORDSIZE - 1) / RECORDSIZE);
  701.         continue;
  702.                     /*
  703.              * If the previous header was good, tell them
  704.              * that we are skipping bad ones.
  705.              */
  706.     case 0:        /* Invalid header */
  707.         switch (prev_status) {
  708.         case 3:        /* Error on first record */
  709.         message (1, " Error ", "Hmm,...\n%s\ndoesn't look like a tar archive.", name);
  710.         /* FALL THRU */
  711.         case 2:        /* Error after record of zeroes */
  712.         case 1:        /* Error after header rec */
  713. #if 0
  714.         message (0, " Warning ", "Skipping to next file header...");
  715. #endif
  716.         case 0:        /* Error after error */
  717.         return -1;
  718.         }
  719.  
  720.     case 2:        /* Record of zeroes */
  721.         status = prev_status;    /* If error after 0's */
  722.         /* FALL THRU */
  723.     case EOF:        /* End of archive */
  724.         break;
  725.     }
  726.     break;
  727.     };
  728.  
  729.     *pparc = archive;
  730.     return 0;
  731. }
  732.  
  733. char *tarfs_analysis (char *name, char **archive, int is_dir)
  734. {
  735.     static struct {
  736.         int len; /* strlen (ext)  */
  737.         char *ext;
  738.     } tarext[] = {{4, ".tar"},
  739.                   {4, ".tgz"},
  740.                   {7, ".tar.gz"},
  741.                   {4, ".taz"},
  742.                   {4, ".tpz"},
  743.           {6, ".tar.z"},
  744.                   {6, ".tar.Z"} };
  745.     char *p, *local;
  746.     unsigned int i;
  747.     char *archive_name = NULL;
  748.  
  749.                                                /*  |  this is len of "tar:" plus some minimum
  750.                                                 *  v  space needed for the extension */
  751.     for (p = name + strlen (name); p >= name + 8; p--)
  752.         if (*p == '/' || (is_dir && !*p))
  753.             for (i = 0; i < sizeof (tarext) / sizeof (tarext [0]); i++)
  754.                 if (!strncmp (p - tarext [i].len, tarext [i].ext, tarext [i].len)) {
  755.                     char c = *p;
  756.                     
  757.                     *p = 0;
  758.                     archive_name = vfs_canon (name + 4);
  759.                     *archive = archive_name;
  760.                     *p = c;
  761.                     local = strdup (p);
  762.                     return local;
  763.                 }
  764.     tarerrno = ENOENT;
  765.     return NULL;
  766. }
  767.  
  768. /* Returns allocated path inside the archive or NULL */
  769. static char *tarfs_get_path (char *inname, struct tarfs_archive **archive, int is_dir,
  770.     int do_not_open)
  771. {
  772.     char *local, *archive_name;
  773.     int result = -1;
  774.     struct tarfs_archive *parc;
  775.     struct vfs_stamping *parent;
  776.     vfs *v;
  777.     
  778.     local = tarfs_analysis (inname, &archive_name, is_dir);
  779.     if (local == NULL) {
  780.         tarerrno = ENOENT;
  781.         return NULL;
  782.     }
  783.     for (parc = first_archive; parc != NULL; parc = parc->next)
  784.         if (!strcmp (parc->name, archive_name)) {
  785.         vfs_stamp (&tarfs_vfs_ops, (vfsid) parc);
  786.         goto return_success;
  787.     }
  788.     if (do_not_open)
  789.         result = -1;
  790.     else
  791.         result = read_tar_archive (archive_name, &parc);
  792.     if (result == -1) {
  793.     tarerrno = EIO;
  794.     free(local);
  795.     free(archive_name);
  796.     return NULL;
  797.     }
  798.     v = vfs_type (archive_name);
  799.     if (v == &local_vfs_ops) {
  800.     parent = NULL;
  801.     } else {
  802.     parent = xmalloc (sizeof (struct vfs_stamping), "vfs stamping");
  803.     parent->v = v;
  804.     parent->id = (*v->getid) (archive_name, &(parent->parent));
  805.     }
  806.     vfs_add_noncurrent_stamps (&tarfs_vfs_ops, (vfsid) parc, parent);
  807. return_success:
  808.     *archive = parc;
  809.     free (archive_name);
  810.     return local;
  811. }
  812.  
  813. struct tarfs_loop_protect {
  814.     struct tarfs_entry *entry;
  815.     struct tarfs_loop_protect *next;
  816. };
  817. static int errloop;
  818. static int notadir;
  819.  
  820. static struct tarfs_entry *
  821. __tarfs_find_entry (struct tarfs_entry *dir, char *name,
  822.             struct tarfs_loop_protect *list, int make_dirs);
  823.  
  824. static struct tarfs_entry *
  825. __tarfs_resolve_symlinks (struct tarfs_entry *entry, 
  826.               struct tarfs_loop_protect *list)
  827. {
  828.     struct tarfs_entry *pent;
  829.     struct tarfs_loop_protect *looping;
  830.     
  831.     if (!S_ISLNK (entry->inode->mode))
  832.         return entry;
  833.     for (looping = list; looping != NULL; looping = looping->next)
  834.         if (entry == looping->entry) { /* Here we protect us against symlink looping */
  835.             errloop = 1;
  836.             return NULL;
  837.         }
  838.     looping = (struct tarfs_loop_protect *)
  839.     xmalloc (sizeof (struct tarfs_loop_protect), 
  840.          "Tar: symlink looping protection");
  841.     looping->entry = entry;
  842.     looping->next = list;
  843.     pent = __tarfs_find_entry (entry->dir, entry->inode->linkname, looping, 0);
  844.     free (looping);
  845.     if (pent == NULL)
  846.         tarerrno = ENOENT;
  847.     return pent;
  848. }
  849.  
  850. static struct tarfs_entry *tarfs_resolve_symlinks (struct tarfs_entry *entry)
  851. {
  852.     struct tarfs_entry *res;
  853.     
  854.     errloop = 0;
  855.     notadir = 0;
  856.     res = __tarfs_resolve_symlinks (entry, NULL);
  857.     if (res == NULL) {
  858.         if (errloop)
  859.             tarerrno = ELOOP;
  860.         else if (notadir)
  861.             tarerrno = ENOTDIR;
  862.     }
  863.     return res;
  864. }
  865.  
  866. static struct tarfs_entry*
  867. __tarfs_find_entry (struct tarfs_entry *dir, char *name, 
  868.              struct tarfs_loop_protect *list, int make_dirs)
  869. {
  870.     struct tarfs_entry *pent, *pdir;
  871.     char *p, *q, *name_end;
  872.     char c;
  873.  
  874.     if (*name == '/') { /* Handle absolute paths */
  875.         name++;
  876.         dir = dir->inode->archive->root_entry;
  877.     }
  878.  
  879.     pent = dir;
  880.     p = name;
  881.     name_end = name + strlen (name);
  882.     q = strchr (p, '/');
  883.     c = '/';
  884.     if (!q)
  885.     q = strchr (p, 0);
  886.     
  887.     for (; pent != NULL && c && *p; ){
  888.     c = *q;
  889.     *q = 0;
  890.  
  891.     if (strcmp (p, ".")){
  892.         if (!strcmp (p, "..")) 
  893.         pent = pent->dir;
  894.         else {
  895.         if ((pent = __tarfs_resolve_symlinks (pent, list))==NULL){
  896.             *q = c;
  897.             return NULL;
  898.         }
  899.         if (c == '/' && !S_ISDIR (pent->inode->mode)){
  900.             *q = c;
  901.             notadir = 1;
  902.             return NULL;
  903.         }
  904.         pdir = pent;
  905.         for (pent = pent->inode->first_in_subdir; pent; pent = pent->next_in_dir)
  906.             /* Hack: I keep the original semanthic unless
  907.                q+1 would break in the strchr */
  908.             if (!strcmp (pent->name, p)){
  909.             if (q + 1 > name_end){
  910.                 *q = c;
  911.                 notadir = !S_ISDIR (pent->inode->mode);
  912.                 return pent;
  913.             }
  914.             break;
  915.             }
  916.         
  917.         /* When we load archive, we create automagically
  918.          * non-existant directories
  919.          */
  920.         if (pent == NULL && make_dirs) { 
  921.             pent = generate_entry (dir->inode->archive, p, pdir, S_IFDIR | 0777);
  922.         }
  923.         }
  924.     }
  925.     /* Next iteration */
  926.     *q = c;
  927.     p = q + 1;
  928.     q = strchr (p, '/');
  929.     if (!q)
  930.         q = strchr (p, 0);
  931.     }
  932.     if (pent == NULL)
  933.         tarerrno = ENOENT;
  934.     return pent;
  935. }
  936.  
  937. static struct tarfs_entry *tarfs_find_entry (struct tarfs_entry *dir, char *name, int make_dirs)
  938. {
  939.     struct tarfs_entry *res;
  940.     
  941.     errloop = 0;
  942.     notadir = 0;
  943.     res = __tarfs_find_entry (dir, name, NULL, make_dirs);
  944.     if (res == NULL) {
  945.         if (errloop)
  946.             tarerrno = ELOOP;
  947.         else if (notadir)
  948.             tarerrno = ENOTDIR;
  949.     }
  950.     return res;
  951. }
  952.  
  953. struct tar_pseudofile {
  954.     struct tarfs_archive *archive;
  955.     long pos;
  956.     long begin;
  957.     long end;
  958.     struct tarfs_entry *entry;
  959. };
  960.  
  961. static void *tar_open (char *file, int flags, int mode)
  962. {
  963.     struct tar_pseudofile *tar_info;
  964.     struct tarfs_archive *archive;
  965.     char *p, *q;
  966.     struct tarfs_entry *entry;
  967.  
  968.     if ((p = tarfs_get_path (file, &archive, 0, 0)) == NULL)
  969.     return NULL;
  970.     q = (*p == '/') ? p + 1 : p;
  971.     entry = tarfs_find_entry (archive->root_entry, q, 0);
  972.     free (p);
  973.     if (entry == NULL)
  974.         return NULL;
  975.     if ((entry = tarfs_resolve_symlinks (entry)) == NULL)
  976.     return NULL;
  977.     if (S_ISDIR (entry->inode->mode)) {
  978.         tarerrno = EISDIR;
  979.         return NULL;
  980.     }
  981.     if (flags & O_ACCMODE != O_RDONLY) {
  982.         tarerrno = EROFS; /* At the moment we are RO */
  983.         return NULL;
  984.     }
  985.     
  986.     tar_info = (struct tar_pseudofile *) xmalloc (sizeof (struct tar_pseudofile), "Tar: tar_open");
  987.     tar_info->archive = archive;
  988.     tar_info->pos = 0;
  989.     tar_info->begin = entry->inode->data_offset;
  990.     tar_info->end = tar_info->begin + entry->inode->size;
  991.     tar_info->entry = entry;
  992.     entry->inode->is_open++;
  993.  
  994.      /* i.e. we had no open files and now we have one */
  995.     vfs_rmstamp (&tarfs_vfs_ops, (vfsid) archive, 1);
  996.     archive->fd_usage++;
  997.     return tar_info;
  998. }
  999.  
  1000. static int tar_read (void *data, char *buffer, int count)
  1001. {
  1002.     struct tar_pseudofile *file = (struct tar_pseudofile *)data;
  1003.  
  1004.     if (file->archive->is_gzipped != targz_growing && 
  1005.         mc_lseek (file->archive->fd, file->begin + file->pos, SEEK_SET) != 
  1006.         file->begin + file->pos) {
  1007.         tarerrno = EIO;
  1008.         return -1;
  1009.     }
  1010.     
  1011.     if (count > file->end - file->begin - file->pos)
  1012.         count = file->end - file->begin - file->pos;
  1013.     if (file->archive->is_gzipped == targz_growing) {
  1014.         char *p = buffer;
  1015.         int cnt = count;
  1016.         int i = file->begin + file->pos, j;
  1017.         
  1018.         if (i % RECORDSIZE) {
  1019.             j = RECORDSIZE - (i % RECORDSIZE);
  1020.             if (cnt < j)
  1021.                 j = cnt;
  1022.             bcopy (((char *) find_current_record (file->archive, i / RECORDSIZE * RECORDSIZE)) + (i % RECORDSIZE),
  1023.                    p, j);
  1024.             cnt -= j;
  1025.             p += j;
  1026.             i += j;
  1027.         }
  1028.         while (cnt) {
  1029.             if (cnt > RECORDSIZE)
  1030.                 j = RECORDSIZE;
  1031.             else
  1032.                 j = cnt;
  1033.             bcopy ((char *) find_current_record (file->archive, i),
  1034.                    p, j);
  1035.             i += j;
  1036.             p += j;
  1037.             cnt -= j;
  1038.         }
  1039.     }
  1040.     else if ((count = mc_read (file->archive->fd, buffer, count)) == -1) {
  1041.         tarerrno = errno;
  1042.         return -1;
  1043.     }
  1044.     file->pos += count;
  1045.     return count;
  1046. }
  1047.  
  1048. static int tar_close (void *data)
  1049. {
  1050.     struct tar_pseudofile *file;
  1051.  
  1052.     file = (struct tar_pseudofile *)data;
  1053.     
  1054.     file->archive->fd_usage--;
  1055.     if (!file->archive->fd_usage) {
  1056.         struct vfs_stamping *parent;
  1057.         vfs *v;
  1058.         
  1059.     v = vfs_type (file->archive->name);
  1060.     if (v == &local_vfs_ops) {
  1061.         parent = NULL;
  1062.     } else {
  1063.         parent = xmalloc (sizeof (struct vfs_stamping), "vfs stamping");
  1064.         parent->v = v;
  1065.         parent->id = (*v->getid) (file->archive->name, &(parent->parent));
  1066.     }
  1067.         vfs_add_noncurrent_stamps (&tarfs_vfs_ops, (vfsid) (file->archive), parent);
  1068.     }
  1069.     (file->entry->inode->is_open)--;
  1070.     
  1071.     free (data);
  1072.     return 0;
  1073. }
  1074.  
  1075. static int tar_errno (void)
  1076. {
  1077.     return tarerrno;
  1078. }
  1079.  
  1080. static void *tar_opendir (char *dirname)
  1081. {
  1082.     struct tarfs_archive *archive;
  1083.     char *p, *q;
  1084.     struct tarfs_entry *entry;
  1085.     struct tarfs_entry **tar_info;
  1086.  
  1087.     if ((p = tarfs_get_path (dirname, &archive, 1, 0)) == NULL)
  1088.     return NULL;
  1089.     q = (*p == '/') ? p + 1 : p;
  1090.     entry = tarfs_find_entry (archive->root_entry, q, 0);
  1091.     free (p);
  1092.     if (entry == NULL)
  1093.         return NULL;
  1094.     if ((entry = tarfs_resolve_symlinks (entry)) == NULL)
  1095.     return NULL;
  1096.     if (!S_ISDIR (entry->inode->mode)) {
  1097.         tarerrno = ENOTDIR;
  1098.         return NULL;
  1099.     }
  1100.  
  1101.     tar_info = (struct tarfs_entry **) xmalloc (sizeof (struct tarfs_entry *), "Tar: tar_opendir");
  1102.     *tar_info = entry->inode->first_in_subdir;
  1103.  
  1104.     return tar_info;
  1105. }
  1106.  
  1107. static void *tar_readdir (void *data)
  1108. {
  1109.     static struct {
  1110.     struct dirent dir;
  1111. #ifdef NEED_EXTRA_DIRENT_BUFFER
  1112.     char extra_buffer [MC_MAXPATHLEN];
  1113. #endif
  1114.     } dir;
  1115.     
  1116.     struct tarfs_entry **tar_info = (struct tarfs_entry **) data;
  1117.     
  1118.     if (*tar_info == NULL)
  1119.         return NULL;
  1120.     
  1121.     strcpy (&(dir.dir.d_name [0]), (*tar_info)->name);
  1122.     
  1123. #ifndef DIRENT_LENGTH_COMPUTED
  1124.     dir.d_namlen = strlen (dir.dir.d_name);
  1125. #endif
  1126.     *tar_info = (*tar_info)->next_in_dir;
  1127.     
  1128.     return (void *)&dir;
  1129. }
  1130.  
  1131. static int tar_closedir (void *data)
  1132. {
  1133.     free (data);
  1134.     return 0;
  1135. }
  1136.  
  1137. static int _tar_stat (char *path, struct stat *buf, int resolve)
  1138. {
  1139.     struct tarfs_archive *archive;
  1140.     char *p, *q;
  1141.     struct tarfs_entry *entry;
  1142.     struct tarfs_inode *inode;
  1143.  
  1144.     if ((p = tarfs_get_path (path, &archive, 0, 0)) == NULL)
  1145.     return -1;
  1146.     q = (*p == '/') ? p + 1 : p;
  1147.     entry = tarfs_find_entry (archive->root_entry, q, 0);
  1148.     free (p);
  1149.     if (entry == NULL)
  1150.         return -1;
  1151.     if (resolve && (entry = tarfs_resolve_symlinks (entry)) == NULL)
  1152.     return -1;
  1153.     inode = entry->inode;
  1154.     buf->st_dev = inode->dev;
  1155.     buf->st_ino = inode->inode;
  1156.     buf->st_mode = inode->mode;
  1157.     buf->st_nlink = inode->nlink;
  1158.     buf->st_uid = inode->uid;
  1159.     buf->st_gid = inode->gid;
  1160. #ifdef HAVE_ST_RDEV
  1161.     buf->st_rdev = inode->rdev;
  1162. #endif
  1163.     buf->st_size = inode->size;
  1164. #ifdef HAVE_ST_BLKSIZE
  1165.     buf->st_blksize = RECORDSIZE;
  1166. #endif
  1167. #ifdef HAVE_ST_BLOCKS
  1168.     buf->st_blocks = (inode->size + RECORDSIZE - 1) / RECORDSIZE;
  1169. #endif
  1170.     buf->st_atime = inode->atime;
  1171.     buf->st_mtime = inode->mtime;
  1172.     buf->st_ctime = inode->ctime;
  1173.     return 0;
  1174. }
  1175.  
  1176. static int tar_stat (char *path, struct stat *buf)
  1177. {
  1178.     return _tar_stat (path, buf, 1);
  1179. }
  1180.  
  1181. static int tar_lstat (char *path, struct stat *buf)
  1182. {
  1183.     return _tar_stat (path, buf, 0);
  1184. }
  1185.  
  1186. static int tar_fstat (void *data, struct stat *buf)
  1187. {
  1188.     struct tar_pseudofile *file = (struct tar_pseudofile *)data;
  1189.     struct tarfs_inode *inode;
  1190.     
  1191.     inode = file->entry->inode;
  1192.     buf->st_dev = inode->dev;
  1193.     buf->st_ino = inode->inode;
  1194.     buf->st_mode = inode->mode;
  1195.     buf->st_nlink = inode->nlink;
  1196.     buf->st_uid = inode->uid;
  1197.     buf->st_gid = inode->gid;
  1198.     buf->st_rdev = inode->rdev;
  1199.     buf->st_size = inode->size;
  1200. #ifdef HAVE_ST_BLKSIZE
  1201.     buf->st_blksize = RECORDSIZE;
  1202. #endif
  1203. #ifdef HAVE_ST_BLOCKS
  1204.     buf->st_blocks = (inode->size + RECORDSIZE - 1) / RECORDSIZE;
  1205. #endif
  1206.     buf->st_atime = inode->atime;
  1207.     buf->st_mtime = inode->mtime;
  1208.     buf->st_ctime = inode->ctime;
  1209.     return 0;
  1210. }
  1211.  
  1212. static int tar_chmod (char *path, int mode)
  1213. {
  1214.     return chmod (path, mode);
  1215. }
  1216.  
  1217. static int tar_chown (char *path, int owner, int group)
  1218. {
  1219.     return chown (path, owner, group);
  1220. }
  1221.  
  1222. static int tar_readlink (char *path, char *buf, int size)
  1223. {
  1224.     struct tarfs_archive *archive;
  1225.     char *p, *q;
  1226.     int i;
  1227.     struct tarfs_entry *entry;
  1228.  
  1229.     if ((p = tarfs_get_path (path, &archive, 0, 0)) == NULL)
  1230.     return -1;
  1231.     q = (*p == '/') ? p + 1 : p;
  1232.     entry = tarfs_find_entry (archive->root_entry, q, 0);
  1233.     free (p);
  1234.     if (entry == NULL)
  1235.         return -1;
  1236.     if (!S_ISLNK (entry->inode->mode)) {
  1237.         tarerrno = EINVAL;
  1238.         return -1;
  1239.     }
  1240.     if (size > (i = strlen (entry->inode->linkname))) {
  1241.         size = i;
  1242.     }
  1243.     strncpy (buf, entry->inode->linkname, i);
  1244.     return i;
  1245. }
  1246.  
  1247. static int tar_unlink (char *path)
  1248. {
  1249.     return -1;
  1250. }
  1251.  
  1252. static int tar_symlink (char *n1, char *n2)
  1253. {
  1254.     return -1;
  1255. }
  1256.  
  1257. static int tar_write (void *data, char *buf, int nbyte)
  1258. {
  1259.     return -1;
  1260. }
  1261.  
  1262. static int tar_rename (char *a, char *b)
  1263. {
  1264.     return -1;
  1265. }
  1266.  
  1267. static int tar_chdir (char *path)
  1268. {
  1269.     struct tarfs_archive *archive;
  1270.     char *p, *q, *res;
  1271.     struct tarfs_entry *entry;
  1272.  
  1273.     tarerrno = ENOTDIR;
  1274.     if ((p = tarfs_get_path (path, &archive, 1, 0)) == NULL)
  1275.     return -1;
  1276.     q = (*p == '/') ? p + 1 : p;
  1277.     entry = tarfs_find_entry (archive->root_entry, q, 0);
  1278.     if (entry == NULL) {
  1279.         free (p);
  1280.         return -1;
  1281.     }
  1282.     entry = tarfs_resolve_symlinks (entry);
  1283.     if (entry == NULL) {
  1284.         free (p);
  1285.         return -1;
  1286.     }
  1287.     if (!S_ISDIR (entry->inode->mode)) {
  1288.         free (p);
  1289.         return -1;
  1290.     }
  1291.     entry->inode->archive->current_dir = entry;
  1292.     res = copy_strings ("tar:", entry->inode->archive->name, p, NULL);
  1293.     free (p);
  1294.     tarerrno = 0;
  1295.     return 0;
  1296. }
  1297.  
  1298. static int tar_lseek (void *data, off_t offset, int whence)
  1299. {
  1300.     struct tar_pseudofile *file = (struct tar_pseudofile *) data;
  1301.  
  1302.     switch (whence) {
  1303.         case SEEK_CUR:
  1304.             offset += file->pos; break;
  1305.         case SEEK_END:
  1306.             offset += file->end - file->begin; break;
  1307.     }
  1308.     if (offset < 0)
  1309.         file->pos = 0;
  1310.     else if (offset < file->end - file->begin)
  1311.         file->pos = offset;
  1312.     else
  1313.         file->pos = file->end;
  1314.     return file->pos;
  1315. }
  1316.  
  1317. static int tar_mknod (char *path, int mode, int dev)
  1318. {
  1319.     return -1;
  1320. }
  1321.  
  1322. static int tar_link (char *p1, char *p2)
  1323. {
  1324.     return -1;
  1325. }
  1326.  
  1327. static int tar_mkdir (char *path, mode_t mode)
  1328. {
  1329.     return -1;
  1330. }
  1331.  
  1332. static int tar_rmdir (char *path)
  1333. {
  1334.     return -1;
  1335. }
  1336.  
  1337. static vfsid tar_getid (char *path, struct vfs_stamping **parent)
  1338. {
  1339.     struct tarfs_archive *archive;
  1340.     vfs *v;
  1341.     vfsid id;
  1342.     char *p;
  1343.     struct vfs_stamping *par;
  1344.  
  1345.     *parent = NULL;
  1346.     if ((p = tarfs_get_path (path, &archive, 0, 1)) == NULL) {
  1347.     return (vfsid) -1;
  1348.     }
  1349.     free (p);
  1350.     v = vfs_type (archive->name);
  1351.     id = (*v->getid) (archive->name, &par);
  1352.     if (id != (vfsid)-1) {
  1353.         *parent = xmalloc (sizeof (struct vfs_stamping), "vfs stamping");
  1354.         (*parent)->v = v;
  1355.         (*parent)->id = id;
  1356.         (*parent)->parent = par;
  1357.         (*parent)->next = NULL;
  1358.     }
  1359.     return (vfsid) archive;    
  1360. }
  1361.  
  1362. static int tar_nothingisopen (vfsid id)
  1363. {
  1364.     if (((struct tarfs_archive *)id)->fd_usage <= 0)
  1365.         return 1;
  1366.     else
  1367.         return 0;
  1368. }
  1369.  
  1370. static void free_entry (struct tarfs_entry *e)
  1371. {
  1372.     int i = --(e->inode->nlink);
  1373.     if (S_ISDIR (e->inode->mode) && e->inode->first_in_subdir != NULL) {
  1374.         struct tarfs_entry *f = e->inode->first_in_subdir;
  1375.         
  1376.         e->inode->first_in_subdir = NULL;
  1377.         free_entry (f);
  1378.     }
  1379.     if (i <= 0) {
  1380.         if (e->inode->linkname != NULL)
  1381.             free (e->inode->linkname);
  1382.         if (e->inode->local_filename != NULL) {
  1383.             unlink (e->inode->local_filename);
  1384.             free (e->inode->local_filename);
  1385.         }
  1386.         free (e->inode);
  1387.     }
  1388.     if (e->next_in_dir != NULL)
  1389.         free_entry (e->next_in_dir);
  1390.     free (e->name);
  1391.     free (e);
  1392. }
  1393.  
  1394. static void tar_free (vfsid id)
  1395. {
  1396.     struct tarfs_archive *parc;
  1397.     struct tarfs_archive *archive = (struct tarfs_archive *)id;
  1398.  
  1399.     free_entry (archive->root_entry);
  1400.     if (archive == first_archive) {
  1401.         first_archive = archive->next;
  1402.     } else {
  1403.         for (parc = first_archive; parc != NULL; parc = parc->next)
  1404.             if (parc->next == archive)
  1405.                 break;
  1406.         if (parc != NULL)
  1407.             parc->next = archive->next;
  1408.     }
  1409.     free_archive (archive);
  1410. }
  1411.  
  1412. static char *tar_getlocalcopy (char *path)
  1413. {
  1414.     struct tarfs_archive *archive;
  1415.     char *p, *q;
  1416.     struct tarfs_entry *entry;
  1417.  
  1418.     if ((p = tarfs_get_path (path, &archive, 1, 0)) == NULL)
  1419.     return NULL;
  1420.     q = (*p == '/') ? p + 1 : p;
  1421.     entry = tarfs_find_entry (archive->root_entry, q, 0);
  1422.     free (p);
  1423.     if (entry == NULL)
  1424.         return NULL;
  1425.     if ((entry = tarfs_resolve_symlinks (entry)) == NULL)
  1426.     return NULL;
  1427.  
  1428.     if (entry->inode->local_filename != NULL)
  1429.         return entry->inode->local_filename;
  1430.     p = mc_def_getlocalcopy (path);
  1431.     if (p != NULL) {
  1432.         entry->inode->local_filename = p;
  1433.     }
  1434.     return p;
  1435. }
  1436.  
  1437. static void tar_ungetlocalcopy (char *path, char *local, int has_changed)
  1438. {
  1439. /* We do just nothing. (We are read only and do not need to free local,
  1440.    since it will be freed when tar archive will be freed */
  1441. }
  1442.  
  1443. #ifdef HAVE_MMAP
  1444. caddr_t tar_mmap (caddr_t addr, size_t len, int prot, int flags, void *data, off_t offset)
  1445. {
  1446.     return (caddr_t)-1;
  1447. }
  1448.  
  1449. int tar_munmap (caddr_t addr, size_t len, void *data)
  1450. {
  1451.     return -1;
  1452. }
  1453. #endif
  1454.  
  1455. vfs tarfs_vfs_ops =
  1456. {
  1457.     tar_open,
  1458.     tar_close,
  1459.     tar_read,
  1460.     tar_write,
  1461.  
  1462.     tar_opendir,
  1463.     tar_readdir,
  1464.     tar_closedir,
  1465.  
  1466.     tar_stat,
  1467.     tar_lstat,
  1468.     tar_fstat,
  1469.  
  1470.     tar_chmod,
  1471.     tar_chown,
  1472.  
  1473.     tar_readlink,
  1474.     tar_symlink,
  1475.     tar_link,
  1476.     tar_unlink,
  1477.  
  1478.     tar_rename,
  1479.     tar_chdir,
  1480.     tar_errno,
  1481.     tar_lseek,
  1482.     tar_mknod,
  1483.     
  1484.     tar_getid,
  1485.     tar_nothingisopen,
  1486.     tar_free,
  1487.     
  1488.     tar_getlocalcopy,
  1489.     tar_ungetlocalcopy,
  1490.     
  1491.     tar_mkdir,
  1492.     tar_rmdir,
  1493.     NULL,
  1494.     NULL
  1495. #ifdef HAVE_MMAP
  1496.     , tar_mmap,
  1497.     tar_munmap
  1498. #endif    
  1499. };
  1500.